cmake_minimum_required(VERSION 2.4.7)
project( divine )

set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake" )

if(COMMAND cmake_policy)
  cmake_policy(SET CMP0002 OLD) # FIXME
  cmake_policy(SET CMP0003 NEW)
endif(COMMAND cmake_policy)

if(NOT CMAKE_BUILD_TYPE)
 set(CMAKE_BUILD_TYPE "Release" CACHE STRING
     "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
     FORCE)
endif(NOT CMAKE_BUILD_TYPE)

macro(appendFlag flags value)
  foreach( F ${flags} )
    set( CMAKE_${F}_FLAGS "${CMAKE_${F}_FLAGS} ${value}" )
  endforeach( F )
endmacro(appendFlag)

option( COIN_LCA "use LCA-based algorithm for CoIn" OFF )
option( PROFILE "generate profiling information for lcov coverage" OFF )
option( HOARD "use HOARD SMP memory allocator" ON )
option( POOLS "use pool allocation for graph vertices" ON )
option( USE64 "pass -m64 to gcc to force 64b on multiarch" OFF )
option( USE32 "pass -m32 to gcc to force 32b on multiarch" OFF )
option( MPI "compile DiVinE with MPI for clustering support" OFF )
option( GUI "compile the Qt GUI" OFF )
option( MURPHI "enable Murphi model compiler" OFF )
include (VersionAppend)

if(CMAKE_BUILD_TYPE STREQUAL "Debug")
    set( PERFORMANCE_DEF OFF )
else()
    set( PERFORMANCE_DEF ON )
endif()

option( PERFORMANCE "compile for maximum performance (LONG compilation)" ${PERFORMANCE_DEF} )

if( COIN_LCA )
  include (CheckIncludeFileCXX)
  CHECK_INCLUDE_FILE_CXX(tr1/unordered_set HAVE_UNORDERED_SET)
  if( HAVE_UNORDERED_SET )
    add_definitions( -DLCA )
  else( HAVE_UNORDERED_SET )
    message("-- WARNING: unordered_set not available. Using recursive algorithm for CoIn.")
  endif( HAVE_UNORDERED_SET ) 
endif( COIN_LCA )

if( WIN32 )
  # PE Executables have fixed stack size and the BISON parser needs a big one
  appendFlag( "EXE_LINKER;SHARED_LINKER" "-Wl,--stack,10485760" )
else()
  add_definitions( -DPOSIX )
endif( WIN32 )

if( PERFORMANCE )
  add_definitions( -DPERFORMANCE )
endif( PERFORMANCE )

if( PROFILE )
  appendFlag( "CXX;C" "-fprofile-arcs -ftest-coverage" )
  link_libraries( "gcov" )
endif( PROFILE )

if( USE64 )
  appendFlag( "CXX;C;EXE_LINKER;SHARED_LINKER" "-m64" )
  add_definitions( -DUSE_GCC_M64 )
endif( USE64 )

if( USE32 )
  appendFlag( "CXX;C;EXE_LINKER;SHARED_LINKER" "-m32" )
  add_definitions( -DUSE_GCC_M32 )
endif( USE32 )

if( NOT POOLS )
  add_definitions( "-DDISABLE_POOLS" )
endif( NOT POOLS )

if( GUI )
  find_package( Qt4 4.5.0 )
endif( GUI )

if( NOT USE32 AND NOT USE64 )
  # the curses package we'd find probably wouldn't work anyway
  find_package( Curses )
  if( CURSES_FOUND )
    add_definitions( -DHAVE_CURSES )
  endif()
endif()

# on some mingw32, regex.h is not on the default include path
find_path( RX_PATH regex.h )
include_directories( ${RX_PATH} )
link_directories( ${RX_PATH} )

if( MPI AND NOT WIN32 )
include( FindMPI )
endif( MPI AND NOT WIN32 )

if( MPI AND MPI_FOUND )
  add_definitions( "-DHAVE_MPI" )
  foreach( path ${MPI_INCLUDE_PATH} )
    set( MPI_INCLUDE_FLAGS "-I${path} ${MPI_INCLUDE_FLAGS}" )
  endforeach()
  include (CheckIncludeFileCXX)
  check_include_file_cxx( "ompi/version.h" HAVE_OMPI_VERSION ${MPI_INCLUDE_FLAGS} )
  if( HAVE_OMPI_VERSION )
    add_definitions( "-DHAVE_OMPI_VERSION" )
  endif()
else()
  set( MPI_INCLUDE_PATH "" )
  set( MPI_LIBRARIES "" )
  set( MPI_LIBRARY "" )
  if( MPI )
    message( "-- WARNING: Could not find MPI. Disabling cluster support." )
  endif( MPI )
  set( MPI OFF )
  set( MPIEXEC "" )
endif()

set( DIVINE_INCLUDES
  ${divine_SOURCE_DIR}
  ${divine_BINARY_DIR}
  ${MPI_INCLUDE_PATH}
  ${divine_SOURCE_DIR}/divine/legacy )

find_program( SHA1SUM sha1sum )

if( NOT SHA1SUM )
  message( "I could use a working sha1sum program for the build. Please install one or supply me with a path if you already have it. Thank you." )
endif( NOT SHA1SUM )

add_custom_target( check )
add_custom_target( unit )

if( PROFILE )
  find_program( LCOV lcov )
  find_program( LCOV_GENHTML genhtml )
  if( NOT LCOV )
    message( "-- WARNING: Could not find LCOV, disabling coverage report generation." )
  endif( NOT LCOV )
endif( PROFILE )

if( LCOV )
  set( LCOV_BIN "${LCOV}" )
  set( LCOV_IN "${divine_BINARY_DIR}" )
  set( LCOV_OUT "${divine_BINARY_DIR}/lcov-report" )
  configure_file( cmake/with-lcov.sh ${divine_BINARY_DIR}/with-lcov )
  execute_process( COMMAND chmod +x ${divine_BINARY_DIR}/with-lcov )
  set( WIBBLE_WRAP_TESTS "${divine_BINARY_DIR}/with-lcov" )

  add_custom_target( lcov-report
    COMMAND mkdir -p ${LCOV_OUT}
    COMMAND ${LCOV} --quiet -b ${divine_SOURCE_DIR} -d ${divine_SOURCE_DIR}
                    -a ${LCOV_OUT}/base.info
                    -a ${LCOV_OUT}/collect-1.info
                    -a ${LCOV_OUT}/collect-2.info
                    -a ${LCOV_OUT}/collect-3.info
                    -o ${LCOV_OUT}/overall_everything.info
    COMMAND ${LCOV} --extract ${LCOV_OUT}/overall_everything.info
                    ${divine_SOURCE_DIR}/divine/*
                    ${divine_SOURCE_DIR}/examples/*
                    ${divine_SOURCE_DIR}/murphi/*
                    ${divine_SOURCE_DIR}/tools/*
                    -o ${LCOV_OUT}/overall.info
    COMMAND ${LCOV_GENHTML} -o lcov-report -p `pwd` -p ${divine_SOURCE_DIR}
      ${LCOV_OUT}/overall.info
    VERBATIM
  )
endif( LCOV )

add_subdirectory( wibble )
if( HOARD )
  add_subdirectory( hoard )
endif( HOARD )
add_subdirectory( lpsolve )

find_program( BYACC "byacc" )
find_package( FLEX )
find_package( BYACC )

if( MURPHI AND FLEX_FOUND AND BYACC_FOUND AND BYACC )
add_subdirectory( murphi )
add_definitions( -DHAVE_MURPHI )
else()
set( MURPHI OFF )
endif()

add_subdirectory( divine )
add_subdirectory( tools )
add_subdirectory( examples )

if( GUI )
  if( QT4_FOUND AND QT_VERSION_MINOR GREATER 4 )
    add_subdirectory( gui )
  else()
    message( "-- WARNING: Could not find Qt4 >= 4.5. Disabling GUI." )
  endif()
endif( GUI )

add_dependencies( check unit )
add_dependencies( check functional )

add_subdirectory( test )

# FIXME: better dependency detection
if( WIN32 )
  macro( bundle var name )
    find_file( ${var} ${name} )
    if( ${var} )
      install( FILES ${${var}} DESTINATION ./ COMPONENT sys)
    endif()
  endmacro()

  bundle( GNURX_LIB libgnurx-0.dll )
  bundle( REGEX_LIB msys-regex-1.dll )
  bundle( GCC_SJL_LIB libgcc_s_sjlj-1.dll )
  bundle( GCC_DW2_LIB libgcc_s_dw2-1.dll )
  bundle( GCC_STDCPP libstdc++-6.dll )
  bundle( MINGW_LIB mingwm10.dll )
  bundle( MSYS_LIB msys-1.0.dll )
endif( WIN32 )

if( WIN32 )
  install(FILES README RENAME README.txt DESTINATION ./ COMPONENT sys)
  install(FILES COPYING RENAME COPYING.txt DESTINATION ./ COMPONENT sys)
  install(FILES AUTHORS RENAME AUTHORS.txt DESTINATION ./ COMPONENT sys)
  install(FILES NEWS RENAME NEWS.txt DESTINATION ./ COMPONENT sys)
else()
  install(FILES README COPYING AUTHORS NEWS DESTINATION share/doc/divine)
endif()

set( CPACK_PACKAGE_DESCRIPTION_SUMMARY "DiViNE Distributed and Parallel Verification Environment" )
set( CPACK_PACKAGE_VENDOR "ParaDiSe Laboratory" )
set( CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/README" )
set( CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING" )

file(STRINGS divine/version.cpp VERSION_LINE REGEX "#define DIVINE_VERSION \"(.*)\"")
string(REGEX REPLACE "#define DIVINE_VERSION \"([0-9.]+)\"" "\\1" VERSION_STRING ${VERSION_LINE})

string(REGEX REPLACE "([0-9])\\.([0-9])\\.([0-9])" "\\1" CPACK_PACKAGE_VERSION_MAJOR ${VERSION_STRING})
string(REGEX REPLACE "([0-9])\\.([0-9])\\.([0-9])" "\\2" CPACK_PACKAGE_VERSION_MINOR ${VERSION_STRING})
string(REGEX REPLACE "([0-9])\\.([0-9])\\.([0-9])" "\\3" CPACK_PACKAGE_VERSION_PATCH ${VERSION_STRING})
set( CPACK_PACKAGE_VERSION ${VERSION_STRING} )

message( "-- Version: ${VERSION_STRING}" )

set( CPACK_PACKAGE_INSTALL_DIRECTORY
      "DiVinE ${CPACK_PACKAGE_VERSION}${VERSION_APPEND}" )
set( CPACK_SOURCE_PACKAGE_FILE_NAME
      "${CMAKE_PROJECT_NAME}-${CPACK_PACKAGE_VERSION}${VERSION_APPEND}" )

if( WIN32 )
  set( CPACK_PACKAGE_FILE_NAME
      "${CMAKE_PROJECT_NAME}-${CPACK_PACKAGE_VERSION}${VERSION_APPEND}-installer" )
endif( WIN32 )

set( CPACK_SOURCE_IGNORE_FILES "/build/;/_build/;/_darcs/;~$;${CPACK_SOURCE_IGNORE_FILES}" )

set( CPACK_COMPONENTS_ALL console_tools gui_tools divine_dev wibble_dev qt sys examples help)

if(WIN32)
  set(CPACK_NSIS_MENU_LINKS "./divine.ide.exe" "DiViNE IDE"
                            "./README.txt" "README"
                            "./COPYING.txt" "COPYING"
                            "./AUTHORS.txt" "AUTHORS"
                            "./NEWS.txt" "NEWS")
  set(CPACK_PACKAGE_EXECUTABLES "" "")
  set(CPACK_NSIS_MODIFY_PATH ON)
endif(WIN32)

include( CPack )

if(CMAKE_MINOR_VERSION EQUAL 6 AND CMAKE_PATCH_VERSION GREATER 0)
  set(HAVE_CMAKE_261 1)
endif()

if(CMAKE_MAJOR_VERSION GREATER 2 OR CMAKE_MINOR_VERSION GREATER 6 OR HAVE_CMAKE_261)
  cpack_add_component_group( tools DISPLAY_NAME "Tools"
                             DESCRIPTION "Installs the basic tools"
                             EXPANDED )

  cpack_add_component_group( devel DISPLAY_NAME "Development"
                             DESCRIPTION "Installs header and library files"
                             EXPANDED )

  cpack_add_component( console_tools DISPLAY_NAME "Console Tools"
                       DESCRIPTION "Console tools"
                       GROUP tools )

  cpack_add_component( gui_tools DISPLAY_NAME "IDE"
                       DESCRIPTION "Graphical environment"
                       GROUP tools )

  cpack_add_component( wibble_dev DISPLAY_NAME "Wibble"
                       DESCRIPTION "Wibble library"
                       GROUP devel )

  cpack_add_component( divine_dev DISPLAY_NAME "Divine"
                       DESCRIPTION "Divine development files"
                       DEPENDS wibble_dev
                       GROUP devel )

  cpack_add_component( help HIDDEN DEPENDS gui_tools )

  cpack_add_component( qt HIDDEN DEPENDS gui_tools )
  cpack_add_component( sys HIDDEN )

  cpack_add_component( examples DISPLAY_NAME "Examples"
                       DESCRIPTION "Sample models" )
endif()
